通过SSE流式调用TongyiBeebotChat。
集成步骤
有关集成时序图与步骤描述如下
依据SSE连接协议,获取SSE访问路径URL,参考文档:SSE流式接口;
通过SSE流式调用TongyiBeebotChat,并通过监听SSE,获取TongyiBeebotChat的流式响应。
重要
获取SSE访问路径URL示例代码:
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.apache.commons.codec.binary.StringUtils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Test {
private static char[] toDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
public static void main(String[] args) throws Exception {
//aliyun账号AK、SK,登录阿里云账号获取
String accessAK = "<你的AK>";
String accessSK = "<你的SK>";
//业务空间AgentKey,获取地址:https://alime.console.aliyun.com/?productCode=p_ics#/business_management/business_management
String agentKey = "<你的AgentKey>";
//机器人实例id,在控制台进入机器人查看
String instanceId = "<你的机器人实例id>";
String question = "<你好>";
ConnectInfo connectInfo = getConnectInfo(accessAK,accessSK,agentKey);
String sseUrl = getSseUrl(connectInfo);
//SSEListener最佳实践,是有前端js实现,我们把sseUrl信息给前端,前端通过js直连SSE,避免从后端中转SSE,降低不必要的网络开销
//前端连sse的库也比较容易,前端直接请求SSE接口,几行代码就够了
new SSEListener(sseUrl,question,instanceId).executeSSE();
}
private static ConnectInfo getConnectInfo(String accessAk,String accessSK,String agentKey) throws ClientException {
String popRegion = "cn-shanghai";
String popProduct = "Chatbot";
String popDomain = "chatbot.cn-shanghai.aliyuncs.com";
DefaultProfile.addEndpoint(popRegion, popProduct, popDomain);
IClientProfile profile = DefaultProfile.getProfile(popRegion, accessAk, accessSK);
profile.getHttpClientConfig().setProtocolType(ProtocolType.HTTPS);
DefaultAcsClient client = new DefaultAcsClient(profile);
//固定入参
//
CommonRequest commonRequest = new CommonRequest();
commonRequest.setSysProduct("Chatbot");
commonRequest.setSysMethod(MethodType.GET);
//根据API会有变化
commonRequest.setSysAction("ApplyForStreamAccessToken");
commonRequest.setSysVersion("2022-04-08");
commonRequest.putQueryParameter("AgentKey",agentKey);
CommonResponse commonResponse = client.getCommonResponse(commonRequest);
return JSONObject.parseObject(commonResponse.getData(), ConnectInfo.class);
}
/**
* /sse/paas4Json/{accessToken}/{channelId}/{sign}/{timestamp}
*/
private static String getSseUrl(ConnectInfo connectInfo) throws NoSuchAlgorithmException {
String timestamp = String.valueOf(System.currentTimeMillis());
String sign = getSigin(connectInfo.getStreamSecret(),timestamp);
return String.format("https://alime-ws.aliyuncs.com/sse/paas4Json/%s/%s/%s/%s",connectInfo.getAccessToken(),connectInfo.getChannelId(),sign,timestamp);
}
private static String getSigin(String streamSecret, String timestamp) throws NoSuchAlgorithmException {
StringBuilder sb = new StringBuilder();
sb.append("streamSecret=").append(streamSecret)
.append("×tamp=").append(timestamp);
byte[] md5Str= md5(sb.toString());
return encodeHex(md5Str,toDigits);
}
private static byte[] md5(String text) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5Bytes = md.digest(StringUtils.getBytesUtf8(text));
return md5Bytes;
}
public static String encodeHex(byte[] data, char[] toDigits) {
int l = data.length;
char[] out = new char[l << 1];
int i = 0;
for(int var5 = 0; i < l; ++i) {
out[var5++] = toDigits[(240 & data[i]) >>> 4];
out[var5++] = toDigits[15 & data[i]];
}
return new String(out);
}
private static class ConnectInfo {
private String accessToken;
private String streamSecret;
private String channelId;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getStreamSecret() {
return streamSecret;
}
public void setStreamSecret(String streamSecret) {
this.streamSecret = streamSecret;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
}
}
以下示例代码包含连接SSE和监听SSE。该段代码仅为调用Tongyibeebotchat接口示例Demo,实际上线可根据业务需求修改。
import com.alibaba.fastjson.JSON;
import okhttp3.Response;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.sse.EventSources;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import java.net.Proxy;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
public class SSEListener extends EventSourceListener {
private static OkHttpClient okHttpClient;
private static ConnectionPool connectionPool = new ConnectionPool(10, 5, TimeUnit.MINUTES);
private String sseUrl;
private String text;
private String instanceId;
public SSEListener(String sseUrl,String text,String instanceId) {
this.sseUrl = sseUrl;
this.text = text;
this.instanceId = instanceId;
}
public void executeSSE() throws Exception {
RequestBody formBody = RequestBody.create(getMessage(), MediaType.parse("application/json; charset=utf-8"));
Request.Builder requestBuilder = new Request.Builder();
Request request = requestBuilder.url(getSseUrl()).post(formBody).build();
EventSource.Factory factory = EventSources.createFactory(getInstance());
//创建事件
factory.newEventSource(request, this);
}
public static OkHttpClient getInstance() {
if (okHttpClient == null) { //加同步安全
synchronized (OkHttpClient.class) {
if (okHttpClient == null) { //okhttp可以缓存数据....指定缓存路径
okHttpClient = new OkHttpClient.Builder()//构建器
.proxy(Proxy.NO_PROXY) //来屏蔽系统代理
.connectionPool(connectionPool)
.connectTimeout(600, TimeUnit.SECONDS)//连接超时
.writeTimeout(600, TimeUnit.SECONDS)//写入超时
.readTimeout(600, TimeUnit.SECONDS)//读取超时
.build();
okHttpClient.dispatcher().setMaxRequestsPerHost(200);
okHttpClient.dispatcher().setMaxRequests(200);
}
}
}
return okHttpClient;
}
/**
* {@inheritDoc}
* 建立sse连接
*/
@Override
public void onOpen(final EventSource eventSource, final Response
response) {
System.out.println("建立sse连接...");
}
/**
* 事件
*
* @param eventSource
* @param id
* @param type
* @param data
*/
@Override
public void onEvent(EventSource eventSource, String id, String type, String data) {
try {
System.out.println("流式返回结果:"+data);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public void onClosed(final EventSource eventSource) {
System.out.println("sse连接关闭...");
}
/**
* {@inheritDoc}
*/
@Override
public void onFailure(final EventSource eventSource, final Throwable t, final Response response) {
System.out.println("onFailure...");
}
// {
// "messageId": "shdlfjldjfldf",
// "action":"TongyiBeebotChat",
// "version":"2022-04-08",
// "data": [
// {
// "type": "JSON_TEXT",
// "value": "{"InstanceId":"xxx","Utterance":"你好"}"
// }
// ]
// }
// */
private String getMessage() {
MessageInfo messageInfo = new MessageInfo();
messageInfo.setMessageId(UUID.randomUUID().toString());
messageInfo.setAction("TongyiBeebotChat");
messageInfo.setVersion("2022-04-08");
List<HashMap> data = new ArrayList<HashMap>();
HashMap<String,String> param = new HashMap<String,String>();
param.put("type","JSON_TEXT");
param.put("value", JSON.toJSONString(new HashMap<String,String>(){
{
put("InstanceId",getInstanceId());
put("Utterance",getText());
}
}));
data.add(param);
messageInfo.setData(data);
return JSON.toJSONString(messageInfo);
}
public String getSseUrl() {
return sseUrl;
}
public void setSseUrl(String sseUrl) {
this.sseUrl = sseUrl;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getInstanceId() {
return instanceId;
}
public void setInstanceId(String instanceId) {
this.instanceId = instanceId;
}
private static class MessageInfo {
private String messageId;
private String action;
private String version;
private List<HashMap> data;
public String getMessageId() {
return messageId;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public List<HashMap> getData() {
return data;
}
public void setData(List<HashMap> data) {
this.data = data;
}
}
}
有关TongyiBeebotChat具体介绍可参考:TongyiBeebotChat。
其他
接口调用建议:由后端生成SSE请求连接所需要的accessToken、channelId、sign、timestamp参数给前端。前端通过js连接SSE,进行流式交互。
反馈
- 本页导读 (0)